﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

//放置RequirComponent()方法的环境
[RequireComponent(typeof(CharacterController))]
public class PointClickMovement : MonoBehaviour
{
    [SerializeField] private Transform target;
    public float rotSpeed = 15.0f;
    public float moveSpeed = 6.0f;

    private float _vertSpeed;
    public float jumpSpeed = 15.0f;
    public float gravity = -9.8f;
    public float terminalVelocity = -10.0f;
    public float minFall = -1.5f;

    private CharacterController _charController;
    //存储碰撞数据
    private ControllerColliderHit _contact;

    private Animator _animator;
    //要应用的力量值
    public float pushForcs = 3.0f;

    public float decleration = 25.0f;
    public float targetBuffer = 1.75f;
    private float _curSpeed = 0f;
    private Vector3 _targetPos = Vector3.one;

    // Use this for initialization
    void Start()
    {
        _animator = GetComponent<Animator>();
        _charController = GetComponent<CharacterController>();
        _vertSpeed = minFall;
    }

    // Update is called once per frame
    void Update()
    {
        Vector3 movement = Vector3.zero;

        //当单击鼠标是设置目标位置
        if (Input.GetMouseButton(0) && !EventSystem.current.IsPointerOverGameObject())
        {
            //在鼠标位置发射射线
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit mouseHit;
            if (Physics.Raycast(ray, out mouseHit))
            {
                GameObject hitObject = mouseHit.transform.gameObject;
                if (hitObject.layer == LayerMask.NameToLayer("Ground"))
                {
                    //将目标位置设置为碰撞位置
                    _targetPos = mouseHit.point;
                    _curSpeed = moveSpeed;
                }
            }
        }
        //如果设置了目标位置,则移动
        if (_targetPos != Vector3.one)
        {
            Vector3 adjustedPos = new Vector3(_targetPos.x, transform.position.y, _targetPos.z);
            Quaternion targetRot = Quaternion.LookRotation(adjustedPos - transform.position);
            //转向目标
            transform.rotation = Quaternion.Slerp(transform.rotation, targetRot, rotSpeed * Time.deltaTime);

            movement = _curSpeed * Vector3.forward;
            movement = transform.TransformDirection(movement);

            if (Vector3.Distance(_targetPos, transform.position) < targetBuffer)
            {
                //当接近目标是减速到0
                _curSpeed -= decleration * Time.deltaTime;
                if (_curSpeed <= 0)
                {
                    _targetPos = Vector3.one;
                }
            }
        }

        _animator.SetFloat("Speed", movement.sqrMagnitude);

        bool hitGround = false;
        RaycastHit hit;
        //检查玩家是否在掉落中
        if (_vertSpeed < 0 && Physics.Raycast(transform.position, Vector3.down, out hit))
        {
            //检查碰撞的距离，稍微超过胶囊体的底部
            float check = (_charController.height + _charController.radius) / 1.9f;
            hitGround = hit.distance <= check;
        }
        //检查控制器是否在地上
        if (hitGround)
        {
            //在地面上时响应Jump键
            if (Input.GetButtonDown("Jump"))
            {
                _vertSpeed = jumpSpeed;
            }
            else
            {
                _vertSpeed = minFall;
                _animator.SetBool("Jumping", false);
            }

        }
        else
        {
            //如果没在地上则应用重力,直到垂直速到到了终止速度
            _vertSpeed += gravity * 5 * Time.deltaTime;
            if (_vertSpeed < terminalVelocity)
            {
                _vertSpeed = terminalVelocity;
            }
            //不在关卡的开始处触发
            if (_contact != null)
            {
                _animator.SetBool("Jumping", true);
            }
            //光线投射没有检测到地面，但胶囊体接触到了地面
            if (_charController.isGrounded)
            {
                //根据角色是否面向接触点,响应稍微不同
                if (Vector3.Dot(movement, _contact.normal) < 0)
                {
                    movement = _contact.normal * moveSpeed;
                }
                else
                {
                    movement += _contact.normal * moveSpeed;
                }
            }
        }
        movement.y = _vertSpeed;

        //将movement乘以deltaTime以使它们帧率独立
        movement *= Time.deltaTime;
        _charController.Move(movement);
    }

    void OnControllerColliderHit(ControllerColliderHit hit)
    {
        //当检测碰撞时将碰撞数据保存在回调中
        _contact = hit;

        //检查碰撞对象是否有Rigidbody，以便接受物理上的外力
        Rigidbody body = hit.collider.attachedRigidbody;
        if (body != null && !body.isKinematic)
        {
            //将速度应用到物理对象上
            body.velocity = hit.moveDirection * pushForcs;
        }
    }
}
